package cn.song.freight.controller;

import cn.song.freight.domain.dto.FreightCalculationRequestDTO;
import cn.song.freight.domain.dto.FreightCalculationResponseDTO;
import cn.song.freight.domain.result.R;
import cn.song.freight.service.FreightCalculationService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;

/**
 * 运费计算控制器
 * <pre>
 * 该控制器处理运费成本计算请求。提供基于重量、目的地区域和定价策略
 * 的运费成本计算端点。支持自动策略选择和手动策略指定。
 *
 * 核心功能：
 * - 自动选择最优策略的运费计算
 * - 指定策略的手动运费计算
 * - 请求验证和错误处理
 * - 全面的日志记录，用于审计和调试
 *
 * @author SongRenShuo
 * @version 3.0.0
 * @since 2025-08-23
 */
@Slf4j
@Api(tags = "运费计算")
@Validated
@RestController
@RequestMapping("/freight")
@RequiredArgsConstructor
public class FreightCalculationController {

    /**
     * 运费计算服务，用于业务逻辑处理
     */
    private final FreightCalculationService freightCalculationService;

    /**
     * 统一运费计算接口
     * <pre>
     * 支持自动策略选择和指定策略两种模式：
     * - 当request.strategyId为空时，系统自动选择最适合的策略
     * - 当request.strategyId有值时，使用指定的策略进行计算
     *
     * @param request 运费计算请求，包含重量、目的地信息和可选的策略ID
     * @return 运费计算结果，包含成本明细和使用的策略信息
     */
    @PostMapping("/calculate")
    @ApiOperation(value = "统一运费计算接口", notes = "支持自动策略选择和指定策略两种模式")
    public R<FreightCalculationResponseDTO> calculateFreight(@Valid @RequestBody FreightCalculationRequestDTO request) {
        log.info("开始统一运费计算: 重量={}kg, 目标区域={}, 策略ID={}", request.getWeight(), request.getToAreaId(), request.getStrategyId());

        FreightCalculationResponseDTO response = freightCalculationService.calculateFreight(request);

        log.info("统一运费计算完成: 费用={}元, 策略={}", response.getFreight(), response.getStrategyName());
        return R.success(response);
    }
}
